package cn.wen233.core.service.impl;

import cn.wen233.basic.exceptions.BaseException;
import cn.wen233.basic.model.Namespace;
import cn.wen233.basic.model.Service;
import cn.wen233.basic.utils.StringUtils;
import cn.wen233.core.filter.ServiceFilter;
import cn.wen233.core.mapper.ServiceMapper;
import cn.wen233.core.page.PageOut;
import cn.wen233.core.service.ServiceService;
import cn.wen233.core.wrapper.query.InstanceQuery;
import cn.wen233.core.wrapper.query.NamespaceQuery;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.InitializingBean;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 持久化 Service 实现类
 *
 * @author wenei
 * @date 2021-10-23 17:08
 */
@org.springframework.stereotype.Service
@RequiredArgsConstructor
public class PersistenceServiceServiceImpl implements ServiceService, InitializingBean {

    private static final ScheduledThreadPoolExecutor SINGLE_THREAD =
            new ScheduledThreadPoolExecutor(1);

    private final ServiceMapper serviceMapper;

    @Override
    public Service findById(String id) {
        return Optional.ofNullable(serviceMapper.selectServiceById(id)).orElseThrow(
                () -> new BaseException("未找到id={%s}的Service", id)
        );
    }

    @Override
    public List<Service> findAll(String namespaceId) {
        return serviceMapper.selectAllService(namespaceId);
    }

    @Override
    public PageOut<Service> findPage(ServiceFilter filter) {
        List<Service> all = findAll(null);
        List<Service> collect = all.stream()
                .filter(service -> {
                    boolean flag = true;
                    if (!StringUtils.isEmpty(filter.getNamespaceId())) {
                        flag = service.getNamespaceId().startsWith(filter.getNamespaceId());
                    }
                    if (!StringUtils.isEmpty(filter.getGroupLike())) {
                        flag = service.getGroupName().startsWith(filter.getGroupLike());
                    }
                    if (!StringUtils.isEmpty(filter.getNameLike())) {
                        flag = flag && service.getName().contains(filter.getNameLike());
                    }
                    return flag;
                })
                .skip((long) filter.getSize() * filter.getNumber())
                .limit(filter.getSize())
                .collect(Collectors.toList());
        return PageOut.of(collect, all.size(), filter.getSize(), filter.getNumber());
    }

    @Override
    public Service findBy(String namespaceId, String group, String serviceName) {
        List<Service> services = serviceMapper.selectAllByNamespaceIdAndGroup(namespaceId, group);
        return services.stream().filter(service -> service.getName().equals(serviceName)).findFirst().orElse(null);
    }

    @Override
    public void create(Service service) {
        // 验证namespaceId是否存在
        NamespaceQuery.getByNamespaceId(service.getNamespaceId());
        // 同一个命名空间中的同一分组只能存在一个同名Service
        if (findAll(service.getNamespaceId()).stream()
                .anyMatch(x -> x.getName().equals(service.getName()) && x.getGroupName().equals(service.getGroupName()))) {
            throw new BaseException("namespaceId={%s}的命名空间的group={%s}已经存在了{%s}的Service", service.getNamespaceId(), service.getGroupName(), service.getName());
        }
        service.setStatus(0);
        serviceMapper.insertService(service);
    }

    @Override
    public void update(String id, Service service) {
        Service entity = serviceMapper.selectServiceById(id);
        entity.setName(service.getName());
        entity.setAppName(service.getAppName());
        entity.setGroupName(service.getGroupName());
        serviceMapper.updateService(entity);
    }

    @Override
    public void delete(String id) {
        findById(id);
        serviceMapper.deleteService(id);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        // 异步检查服务是否可用
        SINGLE_THREAD.scheduleWithFixedDelay(() -> {
            List<Service> serviceList = findAll(null);
            List<String> activeIds = new ArrayList<>();
            List<String> notActiveIds = new ArrayList<>();
            for (Service service : serviceList) {
                Integer instanceCount = InstanceQuery.getServiceInstanceCount(service.getId());
                if (service.getStatus() == 1 && instanceCount == 0) {
                    service.setStatus(0);
                    notActiveIds.add(service.getId());
                    continue;
                }
                if (service.getStatus() == 0 && instanceCount > 0) {
                    service.setStatus(1);
                    activeIds.add(service.getId());
                }
            }
            // todo 更新sql
        }, 500, 3000, TimeUnit.MILLISECONDS);
    }
}
